/* Copyright 2014 Jan Wolter */

#include "stack.h"
#include "bitableau.h"
#include "found.h"

/* This is for tableaus where we can build up or down, steps +1 and -1.
 * Stack moves are NEVER permitted.
 */

/* Array of bitableau piles used in this game */
BiTableauStack *bitableau;
int bitableausize= 0;	/* current size of bitableau array */

/* Does card c2 fit on top of card c1 for building on bitableau column t? */
int bibuildfit(BiTableauStack *t, Card *c1, Card *c2)
{
    return (suitmatch(t->buildsuit, c1->s, c2->s) && (
	    rankmatch(-1, t->basecard, c1->n, c2->n) ||
	    rankmatch(+1, t->basecard, c1->n, c2->n)));
}

/* Return the number of sorted cards on top of the ith BiTableau. This will always
 * be at least one for non-empty stacks.
 */
/*
int binsorted(i)
{
    Stack *s= stacks + bitableau[i].id;
    if (s->n < 2) return s->n;
    for (int n= 1; n < s->n; n++)
	if (!bibuildfit(bitableau+i, s->c[s->n-n], s->c[s->n-n-1]))
	    return n;
    return s->n;
}
*/

int bitableau_mayInsert(Stack *dst, Card *card, int len, Stack *src)
{
    int next;
    Stack *nextstack;
    BiTableauStack *t= bitableau + dst->tid;
    Card *topdst= topStack(dst);

    /* Moving to empty stack */
    if (dst->n == 0)
    {
	/* Empty stack - only the leftmost empty stack may be played into */
	/* We do this to reduce the number of possible moves */
	for (int i= t->beginset; i < dst->tid; i++)
	    if (stacks[bitableau[i].id].n == 0) return 0;

	/* Don't allow the move if it would empty another bitableau stack. This
	 * prevents infinite loops of moving kings back and forth between
	 * empty stacks.
	 */
	if (src->type == TABLEAU && len == src->n &&
	    (t->fillblank != F_KINGLEFT || src->tid != dst->tid+1) &&
	    bitableau[src->tid].fillblank != S_NONE)
	    return 0;

	/* otherwise fillblank determine what we can do */
	switch (t->fillblank)
	{
	    case F_ANYTHING:
		return 1;
	    case F_KINGONLY:
		return (card->n == 13);
	    case F_KINGLEFT:
		next= dst->tid+1;
		/* If the next bitableau column is empty or non-existent, then
		 * any king may be moved in */
		if (next == nbitableau ||
		    (nextstack= stacks+bitableau[next].id)->n == 0)
		    return (card->n == 13);
		/* Otherwise only moves from that next column are allowed */
		if (nextstack != src) return 0;
		/* And they must be moves of maximal movable stacks */
		int i= src->n - len - 1;
		return (i < 0 || !bibuildfit(bitableau+next, src->c[i], card));
	    case F_NONE:
	    default:
		return 0;
	}
    }
    else if (src->type == TABLEAU && ndeck > 1 && src->n > len)
    {
	/* Don't move the JH back and fourth between two QH cards either */
	Card *topsrc= src->c[src->n - len - 1];
	if (topsrc->n == topdst->n && topsrc->s == topdst->s)
	    return 0;
    }

    return bibuildfit(t,topdst,card);
}

/* After cards have been removed, make sure the the top card is face up.
 * Autofills would probably go here too.
 */
/*
void bitableau_postMove(Stack *stack)
{
    Card *c= topStack(stack);
    if (c) c->faceup= 1;
}
*/

int bitableau_firstMove(Stack *stack, int *index1, int *len)
{
    if (stack->n == 0) return 0;

    /* This is our normal first move - just removing the top card
     * Even in games where we don't break sequences, we will still want to
     * try that so we can move single cards to the foundation.
     */
    *index1= stack->n-1;
    *len= 1;

    /* But in rare circumstance we won't want to do that. Like when we are only
     * moving complete sequences to the foundation, and there is more than one
     * faceup card on the stack. */
    if (superfound == sf_complete && stack->n > 1 && stack->c[stack->n-2]->faceup)
	return bitableau_nextMove(stack, index1, len);

    /* Just return the single card move */
    return 1;
}

int bitableau_nextMove(Stack *stack, int *index1, int *len)
{
    BiTableauStack *t= bitableau + stack->tid;

    if (*len == 1)
    {
	/* Doing the second move - find the longest possible movable sequence */
	/* Though we don't technically allow sequence moves, any sequence is
	 * movable if (1) there is an empty space, and (2) the top card of our
	 * sequence can be placed in that empty space.
	 */
	int supermove= 0;
	for (int k= 0; k < nbitableau; k++)
	{
	    Stack *ks= stacks+bitableau[k].id;
	    int fb= bitableau[k].fillblank;
	    if (ks->n == 0 && (fb == F_ANYTHING ||
			((fb == F_KINGONLY || fb == F_KINGLEFT) &&
			 topStack(stack)->n == 12 ) ))
	    {
		supermove= 1;
		break;
	    }
	}
	if (!supermove) return 0;

	int i;
	for (i= *index1 - 1; i >= 0; i--)
	{
	    if (!bibuildfit(t, stack->c[i], stack->c[i+1]))
		break;
	}
	/* i is now the index of the topmost unmovable card */
	if (i == *index1 - 1) return 0;
	*index1= i+1;
	*len= stack->n - *index1;
    }
    else 
	/* When we do a sequence move, it is always the full sequence, so we never
	 * do shorter sequences. So there are at most two possible moves to propose */
	return 0;
}

#ifndef HAVE_TABLEAU	/* identical to version in tableau.c */
int isfaceup(int dealflip, int i)
{
    switch (dealflip)
    {
	case FLIP_NONE: return 1;
	case FLIP_ALL: return 0;
    }
}
#endif

void makeBiTableau(int ndeal, int dealflip, Stack *deal,
    int buildsuit, int basecard, int fillblank, int beginset)
{
    /* Make sure we have memory for another bitableau pile */
    if (bitableausize == 0)
    {
	bitableausize= 8;
	bitableau= (BiTableauStack *)malloc(bitableausize*sizeof(BiTableauStack));
    }
    else if (nbitableau == bitableausize)
    {
	bitableausize+= 8;
	bitableau= (BiTableauStack *)realloc(bitableau,bitableausize*sizeof(BiTableauStack));
    }

    /* Create the bitableau pile */
    bitableau[nbitableau].buildsuit= buildsuit;
    bitableau[nbitableau].fillblank= fillblank;
    bitableau[nbitableau].beginset= beginset;
    bitableau[nbitableau].basecard= basecard;

    /* It starts out with ncards, but if we are allowing building we increase
     * that. */
    int size= ndeal;
    if (buildsuit != S_NONE)
    {
	size*= 2;
	if (size < npip) size= npip;
	if (size > ncard) size= ncard;
    }

    int i= bitableau[nbitableau].id= newStack(TABLEAU,nbitableau,size,
	    (buildsuit == S_NONE) ? NULL : bitableau_mayInsert,
	    bitableau_firstMove, bitableau_nextMove,
	    NULL);

    /* Deal in the cards */
    for (int j= 0; j < ndeal; j++)
    {
	Card *c= popStack(deal);
	if (c == NULL) break;
	c->faceup= (j == ndeal-1 || isfaceup(dealflip, j));
	pushStack(stacks+i, c);
    }
    nbitableau++;
}

void cleanBiTableau()
{
    free(bitableau);
    nbitableau= bitableausize= 0;
}

void printBiTableau(FILE *f, Stack *stks)
{
    char label[8];
    for (int k= 0; k < nbitableau; k++)
    {
	sprintf(label,"T%02d", k+1);
	printStack(f, label, stks+bitableau[k].id);
    }
}


/* Append all bitableau cards to the given stack, first the face up ones, in
 * reverse order, then the facedown ones, in the original order. The bitableau
 * stacks are not altered.
 */
void gatherBiTableau(Stack *s, int rev)
{
    /* Gather face up cards on top of each stack, reversing them */
    for (int k= 0; k < nbitableau; k++)
    {
	Stack *fs= stacks+bitableau[k].id;
	for (int i= fs->n-1; i >= 0; i--)
	{
	    Card *c= fs->c[rev ? fs->n-i-1 : i];
	    if (c->faceup)
		pushStack(s, c);
	}
    }

    /* Now gather up all the face down cards, not reversing them. */
    for (int k= 0; k < nbitableau; k++)
    {
	Stack *fs= stacks+bitableau[k].id;
	for (int i= 0; i < fs->n; i++)
	{
	    Card *c= fs->c[rev ? fs->n-i-1 : i];
	    if (!c->faceup)
		pushStack(s, c);
	}
    }
}
